package com.bird.thread.base.background;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author: bird
 * @Data: 2021/7/5 11:18
 * @description: 验证：
 * 1:    a++操作,在多线程操作的情况下导致结果错误。
 * 2:   并记录哪次操作导致的记录错误。
 */
public class MultiThreadsError1 implements Runnable {

    private Object lock = new Object();

    static int index = 0;

    // 使用原子类 可以保证index++ 以原子的形式金
    private static AtomicInteger realIndex = new AtomicInteger();
    private static AtomicInteger wrongIndex = new AtomicInteger();

    //cyclicBarrier的作用：让我们的线程根据我们的需要在某一个地方等待,
    // 直到所有的人员都就绪了,我们再一起出发 参数是 几个线程的意思
    static volatile CyclicBarrier cyclicBarrier1 = new CyclicBarrier(2);
    static volatile CyclicBarrier cyclicBarrier2 = new CyclicBarrier(2);

    // 定义一个数组 用来标记每个元素是否都操作过。
    private boolean[] marked = new boolean[1000000];
    static MultiThreadsError1 runnable = new MultiThreadsError1();

    public static void main(String[] args) throws InterruptedException {

        Thread thread1 = new Thread(runnable);
        Thread thread2 = new Thread(runnable);
        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();
        System.out.println("表面上的结果：" + index);
        System.out.println("实际的次数：" + realIndex);
        System.out.println("错误的次数：" + wrongIndex);
    }


    @Override
    public void run() {
        for (int i = 0; i < 10000; i++) {
            try {
                // 让所有的线程执行 都在这里等待
                cyclicBarrier2.reset();
                cyclicBarrier1.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
            index++;

            try {
                // 同上 当所有的线程都执行到这行代码时 需要等待  然后一起出发
                cyclicBarrier1.reset();
                cyclicBarrier2.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }

            realIndex.incrementAndGet();// 真正运行的次数
            synchronized (runnable) {
                if (marked[index] && marked[index - 1]) {
                    System.out.println("发生了错误 " + index);
                    wrongIndex.incrementAndGet();// 统计错误的次数
                }
                marked[index] = true;
            }
        }
    }
}
